package com.decent.exception;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.decent.entity.common.Message;
import com.decent.entity.common.MyException;
import com.decent.enums.MessageEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Objects;

/**
 * @Author decent
 * @Create 2021/4/12 - 11:22
 * @Description
 */
@RestControllerAdvice
public class ExceptionAdvice {

    Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * token校验异常
     * @param jwtVerificationException jwtVerificationException
     * @return message
     */
    @ExceptionHandler(JWTVerificationException.class)
    public Message handleMyException(JWTVerificationException jwtVerificationException) {

        // 日志保存异常的信息
        logger.error("服务出错:"+jwtVerificationException.getMessage());

        // 设置返回的响应的头部异常码以及信息
        return new Message(MessageEnum.TOKEN_EXPIRED);
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Message bindException(MethodArgumentTypeMismatchException methodArgumentTypeMismatchException) {
        logger.error("参数类型出错:" + methodArgumentTypeMismatchException.getMessage());
        return new Message(MessageEnum.PARAM_ERROR);
    }

    /**
     * 自定义异常
     * @param myException 自定义异常
     * @return 错误信息
     */
    @ExceptionHandler(MyException.class)
    public Message myException(MyException myException) {
        logger.error("服务出错:" + myException.getMessage());
        Message message = new Message(myException.getCode(), myException.getMessage());
        if (Objects.nonNull(myException.getCode())) {
            message.setErrorCode(MessageEnum.NULL_MSG.getStatus());
        }

        return message;
    }
    /**
     * 校验错误拦截处理
     *
     * @param exception 错误信息集合
     * @return 错误信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Message validationBodyException(MethodArgumentNotValidException exception) {
        //对校验错误信息进行封装，并输出到日志
        BindingResult result = exception.getBindingResult();
        StringBuilder errorMessage = new StringBuilder();
        if (result.hasErrors()) {

            List<ObjectError> errors = result.getAllErrors();
            errors.forEach(p -> {

                FieldError fieldError = (FieldError) p;
                logger.error(MessageEnum.VALID_ERROR + "：数据校验错误 : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
                        "},errorMessage{" + fieldError.getDefaultMessage() + "}");
                errorMessage.append(fieldError.getDefaultMessage());
            });

        }
        //封装错误到响应信息
        Message message = new Message();
        message.setErrorMsg(errorMessage.toString());
        message.setErrorCode(MessageEnum.VALID_ERROR.getStatus());
        return message;
    }

    /**
     * 注解@NOTNULL错误拦截处理
     *
     * @param exception 错误信息集合
     * @return 错误信息
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Message constraintViolationException(HttpServletRequest request, ConstraintViolationException exception) {
        // 日志保存异常的信息
        logger.error("url [{}] params [{}] error ", request.getRequestURI(), JSON.toJSONString(request.getParameterMap()), exception);
        //设置返回的响应的头部异常码以及信息
        StringBuilder sb = new StringBuilder();
        String[] split = exception.getMessage().split(",");
        for (String errorStr : split) {
            if (sb.length() > 0)  {
                sb.append(",");
            }
            String error = errorStr.split(":")[1].trim();
            sb.append(error);
        }
        Message message = new Message(MessageEnum.GENERAL_REQUEST_ERROR);
        message.setErrorMsg(sb.toString());

        return message;
    }

    /**
     * 请求方式不支持
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public Message handleException(HttpRequestMethodNotSupportedException e) {
        logger.error(e.getMessage(), e);
        return new Message(MessageEnum.PARAM_ERROR);
    }

    /**
     * 请求的数据格式错误的处理
     * @param e HttpMessageNotReadableException
     * @return message
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Message handleException(HttpMessageNotReadableException e) {
        logger.error(e.getMessage(), e);
        return new Message(MessageEnum.PARAM_ERROR);
    }

    /**
     * 其他异常处理
     * @param request request
     * @param exception Exception
     * @return message
     */
    @ExceptionHandler(Exception.class)
    public Message handleMyException(HttpServletRequest request, Exception exception) {

        // 日志保存异常的信息
        logger.error("url [{}] params [{}] error ", request.getRequestURI(), JSON.toJSONString(request.getParameterMap()), exception);
        //设置返回的响应的头部异常码以及信息
        Message message = new Message(MessageEnum.GENERAL_REQUEST_ERROR);

        return message;
    }


}
